package com.hn.common.utils.ding.process;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.dingtalk.api.request.OapiProcessSaveRequest;
import com.hn.common.utils.ding.process.Process;
import com.hn.common.utils.ding.process.ProcessFormType;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 描述:
 * 审批模板 明细组件的子组件
 *
 * @author fei
 * 2019-07-10 10:19
 */
public class ProcessDetailModel {

    /**
     * 注意，每种表单组件，对应的componentName是固定的，参照一下示例代码
     */
    private List<OapiProcessSaveRequest.FormComponentVo2> children = new ArrayList<>();

    /**
     * 单行文本框
     * @param label    表单名称
     * @param required 是否必填
     * @return  {@link com.hn.utils.dingtalk.domain.ProcessDetailModel}
     */
    public ProcessDetailModel singleInput(String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 singleInput = setBasicProp(
                "TextField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo singleInputProp = singleInput.getProps();
        children.add(singleInput);
        return this;
    }

    /**
     * 多行文本框
     * @param label    表单名称
     * @param required 是否必填
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel multipleInput(String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 multipleInput = setBasicProp(
                "TextareaField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo multipleInputProp = multipleInput.getProps();
        children.add(multipleInput);
        return this;
    }

    /**
     * 金额组件
     *
     * @param label    表单名称
     * @param required 是否必填
     * @param notUpper 是否需要大写 默认是需要;
     *                 1:不需要大写,
     *                 空或者0:需要大写
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel moneyComponent(String label, Boolean required, String notUpper) {
        OapiProcessSaveRequest.FormComponentVo2 moneyComponent = setBasicProp(
                "MoneyField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo moneyComponentProp = moneyComponent.getProps();
        // 是否禁用大写
        moneyComponentProp.setNotUpper(notUpper);
        children.add(moneyComponent);
        return this;
    }

    /**
     * 数字输入框
     *
     * @param label    表单名称
     * @param required 是否必填
     * @param unit 数字组件单位属性。
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel numberComponent(String label, Boolean required, String unit) {
        OapiProcessSaveRequest.FormComponentVo2 numberComponent = setBasicProp(
                "NumberField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo numberComponentProp = numberComponent.getProps();
        numberComponentProp.setUnit(unit);
        children.add(numberComponent);
        return this;
    }

    /**
     * 计算公式
     * @param label    表单名称
     * @param required 是否必填
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel calculateComponent(String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 calculateComponent = setBasicProp(
                "CalculateField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo calculateComponentProp = calculateComponent.getProps();
        calculateComponentProp.setPlaceholder("自动计算数值");
        children.add(calculateComponent);
        return this;
    }

    /**
     * 单选框
     * @param label    表单名称
     * @param required 是否必填
     * @param options 单选框的选项 选项最多200项，每项最多50个字
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel selectComponent(String label, Boolean required, List<String> options) {
        OapiProcessSaveRequest.FormComponentVo2 selectComponent = setBasicProp(
                "DDSelectField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo selectComponentProp = selectComponent.getProps();
        // 选项最多200项，每项最多50个字
        selectComponentProp.setOptions(options);
        children.add(selectComponent);
        return this;
    }

    /**
     * 多选框
     * @param label    表单名称
     * @param required 是否必填
     * @param options 选项值
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel multiSelectComponent(String label, Boolean required, List<String> options) {
        OapiProcessSaveRequest.FormComponentVo2 multiSelectComponent = setBasicProp(
                "DDMultiSelectField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo multiSelectComponentProp = multiSelectComponent.getProps();
        multiSelectComponentProp.setOptions(options);
        children.add(multiSelectComponent);
        return this;
    }

    /**
     * 日期
     * @param label    表单名称
     * @param required 是否必填
     * @param unit 日期区间组件单位属性 只能填小时和天
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel dateComponent(String label, Boolean required, String unit) {
        OapiProcessSaveRequest.FormComponentVo2 dateComponent = setBasicProp(
                "DDDateField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo dateComponentProp = dateComponent.getProps();
        // 小时或天
        dateComponentProp.setUnit(unit);
        children.add(dateComponent);
        return this;
    }

    /**
     * 日期区间
     *
     * @param beginLabel 开始时间表单名称
     * @param endLabel   结束时间表单名称
     * @param required   是否必填
     * @param unit       日期区间组件单位属性 只能填小时和天
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel dateRangeComponent(String beginLabel, String endLabel, Boolean required, String unit) {
        // 日期区间
        OapiProcessSaveRequest.FormComponentVo2 dateRangeComponent = new OapiProcessSaveRequest.FormComponentVo2();
        dateRangeComponent.setComponentName("DDDateRangeField");
        OapiProcessSaveRequest.FormComponentPropVo dateRangeComponentProp = new OapiProcessSaveRequest.FormComponentPropVo();
        dateRangeComponentProp.setRequired(required);
        dateRangeComponentProp.setLabel(JSONUtil.toJsonStr(Arrays.asList(beginLabel, endLabel)));
        dateRangeComponentProp.setPlaceholder("请选择");
        // 小时或天
        dateRangeComponentProp.setUnit(unit);
        dateRangeComponentProp.setNotPrint("1");
        dateRangeComponentProp.setId("DDDateRangeField-" + RandomUtil.randomString(8));
        dateRangeComponent.setProps(dateRangeComponentProp);
        children.add(dateRangeComponent);
        return this;
    }

    /**
     * 关联组件
     * @param label    表单名称
     * @param required 是否必填
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel relateComponent(String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 relateComponent = setBasicProp(
                "RelateField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo relateComponentProp = relateComponent.getProps();
        children.add(relateComponent);
        return this;
    }

    /**
     * 图片
     * @param label    表单名称
     * @param required 是否必填
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel photoComponent(String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 photoComponent = setBasicProp(
                "DDPhotoField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo photoComponentProp = photoComponent.getProps();
        children.add(photoComponent);
        return this;
    }


    /**
     * 附件
     * @param label    表单名称
     * @param required 是否必填
     * @return  {@link ProcessDetailModel}
     */
    public ProcessDetailModel attachmentComponent(String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 attachmentComponent = setBasicProp(
                "DDAttachment", label, required);
        OapiProcessSaveRequest.FormComponentPropVo attachmentComponentProp = attachmentComponent.getProps();
        children.add(attachmentComponent);
        return this;
    }

    /**
     * 内部联系人
     * @param label    表单名称
     * @param required 是否必填
     * @param choice 是否支持多选 "1" or "0"
     * @return {@link ProcessDetailModel}
     */
    public ProcessDetailModel innerContactComponent(String label, Boolean required, Long choice) {
        OapiProcessSaveRequest.FormComponentVo2 innerContactComponent = setBasicProp(
                "InnerContactField", label, required);
        OapiProcessSaveRequest.FormComponentPropVo innerContactComponentProp = innerContactComponent.getProps();
        // 是否支持多选 "1" or "0"
        innerContactComponentProp.setChoice(choice);
        children.add(innerContactComponent);
        return this;
    }

    private OapiProcessSaveRequest.FormComponentVo2 setBasicProp(String componentName, String label, Boolean required) {
        OapiProcessSaveRequest.FormComponentVo2 formComponent = new OapiProcessSaveRequest.FormComponentVo2();
        formComponent.setComponentName(componentName);
        OapiProcessSaveRequest.FormComponentPropVo formComponentProp = new OapiProcessSaveRequest.FormComponentPropVo();
        // 表单组件id，必须在模板里唯一。有两段字符串组成。第一段为表单的component_name；第二段为8位随机字符串
        formComponentProp.setId(componentName + "-" + RandomUtil.randomString(8));
        // 是否必填
        formComponentProp.setRequired(required);
        // 表单名称
        formComponentProp.setLabel(label);
        // 占位提示（仅输入类组件）
        formComponentProp.setPlaceholder("请输入" + label);
        // 是否参与打印(1表示不打印, 0表示打印)
        formComponentProp.setNotPrint("1");
        // 表单属性
        formComponent.setProps(formComponentProp);
        return formComponent;
    }

    public List<OapiProcessSaveRequest.FormComponentVo2> getChildren() {
        return children;
    }


    /**
     * class 转 ProcessModel
     *
     * @param clazz Class
     * @return ProcessDetailModel
     */
    public static ProcessDetailModel convert(Class clazz) {
        ProcessDetailModel processDetailModel = new ProcessDetailModel();
        // 有数据时才处理 得到类的所有field.
        Field[] allFields = clazz.getDeclaredFields();
        for (int col = 0; col < allFields.length; col++) {
            Field field = allFields[col];
            Process process = field.getAnnotation(Process.class);
            if (process != null) {
                // 取得类型
                ProcessFormType processFormType = process.formType();
                if (ProcessFormType.TextField.equals(processFormType)) {
                    processDetailModel.singleInput(process.name(), process.required());
                } else if (ProcessFormType.TextareaField.equals(processFormType)) {
                    processDetailModel.multipleInput(process.name(), process.required());
                }  else if (ProcessFormType.DDMultiSelectField.equals(processFormType)) {
                    String options = process.options();
                    List optionList = null;
                    if (StrUtil.isNotBlank(options)) {
                        String[] split = options.split(",");
                        optionList = Arrays.asList(split);
                    }
                    processDetailModel.multiSelectComponent(process.name(), process.required(), optionList);
                } else if (ProcessFormType.DDDateField.equals(processFormType)) {
                    processDetailModel.dateComponent(process.name(), process.required(), process.unit());
                } else if (ProcessFormType.MoneyField.equals(processFormType)) {
                    processDetailModel.moneyComponent(process.name(), process.required(), process.unit());
                } else if (ProcessFormType.DDAttachment.equals(processFormType)) {
                    processDetailModel.attachmentComponent(process.name(), process.required());
                } else if (ProcessFormType.DDSelectField.equals(processFormType)) {
                    String options = process.options();
                    List optionList = null;
                    if (StrUtil.isNotBlank(options)) {
                        String[] split = options.split(",");
                        optionList = Arrays.asList(split);
                    }
                    processDetailModel.selectComponent(process.name(), process.required(), optionList);
                }
            }
        }
        return processDetailModel;
    }

}
